/*
 * Copyright (c) 2008, Spagettikod | Stockholm
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the Spagettikod | Stockholm nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.spagettikod.t437;

import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import com.xerox.amazonws.sdb.Domain;
import com.xerox.amazonws.sdb.ListDomainsResult;
import com.xerox.amazonws.sdb.SDBException;

public class AWSJTree extends JTree implements TreeSelectionListener, TreeWillExpandListener, ActionListener
{

	private static final long serialVersionUID = -3180690210311801788L;

	private static final DefaultMutableTreeNode ROOT_NODE = new DefaultMutableTreeNode("root");

	protected static DefaultMutableTreeNode SIMPLE_DB_NODE = new DefaultMutableTreeNode("SimpleDB");

	private T437 t437;

	private JPopupMenu simpleDBPopupMenu;

	private JPopupMenu domainPopupMenu;

	private DomainMutableTreeNode domainNodeInPopup;

	public AWSJTree(T437 t437)
	{
		super(ROOT_NODE);

		this.t437 = t437;

		getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		addTreeSelectionListener(this);
		addTreeWillExpandListener(this);
		setShowsRootHandles(true);
		setCellRenderer(new AWSTreeCellRenderer());

		ROOT_NODE.add(SIMPLE_DB_NODE);

		// Hide the root node
		expandRow(0);
		setRootVisible(false);

		createPopupMenus();
	}

	private void createPopupMenus()
	{
		simpleDBPopupMenu = new JPopupMenu();
		JMenuItem menuItem = new JMenuItem("Refresh");
		menuItem.setActionCommand("refreshAllDomains");
		menuItem.addActionListener(this);
		simpleDBPopupMenu.add(menuItem);

		domainPopupMenu = new JPopupMenu();
		menuItem = new JMenuItem("Refresh");
		menuItem.setActionCommand("refreshDomain");
		menuItem.addActionListener(this);
		domainPopupMenu.add(menuItem);

		MouseListener popupListener = new PopupListener();
		addMouseListener(popupListener);
	}

	private void loadSimpleDBDomains(boolean forceLoad)
	{
		if (SIMPLE_DB_NODE.getChildCount() == 0 || forceLoad)
		{
			try
			{
				getTopLevelAncestor().setCursor(new Cursor(Cursor.WAIT_CURSOR));
				SIMPLE_DB_NODE.removeAllChildren();
				ListDomainsResult domainsResult = t437.getSimpleDB().listDomains();
				if (domainsResult != null)
				{
					List<Domain> domains = domainsResult.getDomainList();
					for (Domain d : domains)
					{
						DomainMutableTreeNode node = new DomainMutableTreeNode(d);
						node.setAllowsChildren(false);
						SIMPLE_DB_NODE.add(node);
					}
				}
				((DefaultTreeModel) getModel()).nodeStructureChanged(SIMPLE_DB_NODE);
			}
			catch (SDBException e)
			{
				e.printStackTrace();
				JOptionPane.showMessageDialog(getTopLevelAncestor(), e.getLocalizedMessage(),
						"AWS Communication Error", JOptionPane.ERROR_MESSAGE);
			}
			finally
			{
				getTopLevelAncestor().setCursor(Cursor.getDefaultCursor());
			}
		}
	}

	private void loadDomain(Domain domain)
	{
		getTopLevelAncestor().setCursor(new Cursor(Cursor.WAIT_CURSOR));

		SimpleDBTableModel tableModel = new SimpleDBTableModel(t437.getSimpleDB());
		JTable table = new JTable(tableModel);

		tableModel.loadDomain(domain);
		JScrollPane tablePane = new JScrollPane(table);
		/*
		 * tablePane.getVerticalScrollBar().addAdjustmentListener(new
		 * AdjustmentListener() {
		 * 
		 * public void adjustmentValueChanged(AdjustmentEvent e) { if
		 * (!e.getValueIsAdjusting()) { JScrollBar bar = (JScrollBar)
		 * e.getSource(); System.out.println(e.getValue() + " " +
		 * bar.getMaximum()); if (e.getValue() == bar.getMaximum()) {
		 * System.out.println("bottom"); } } }
		 * 
		 * });
		 */
		t437.setRightPane(tablePane);

		getTopLevelAncestor().setCursor(Cursor.getDefaultCursor());
	}

	// TreeSelectionListener handler

	public void valueChanged(TreeSelectionEvent e)
	{
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) getLastSelectedPathComponent();

		if (node == null)
			return;

		Object userObject = node.getUserObject();

		if (userObject instanceof Domain)
		{
			loadDomain((Domain) userObject);
		}
		else if (node.equals(SIMPLE_DB_NODE))
		{
			loadSimpleDBDomains(false);
			if (SIMPLE_DB_NODE.getChildCount() > 0)
			{
				expandPath(new TreePath(SIMPLE_DB_NODE.getPath()));
			}
		}
	}

	// TreeWillExpandListener handlers

	public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException
	{
	}

	public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException
	{
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) event.getPath().getLastPathComponent();

		if (node == null)
			return;

		if (node.equals(SIMPLE_DB_NODE))
		{
			loadSimpleDBDomains(false);
		}
	}

	// ActionListener handler

	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		if (command.equals("refreshAllDomains"))
		{
			loadSimpleDBDomains(true);
		}
		else if (command.equals("refreshDomain"))
		{
			loadDomain(domainNodeInPopup.getDomain());
		}
	}

	class PopupListener extends MouseAdapter
	{

		@Override
		public void mousePressed(MouseEvent e)
		{
			maybeShowPopup(e);
		}

		@Override
		public void mouseReleased(MouseEvent e)
		{
			maybeShowPopup(e);
		}

		private void maybeShowPopup(MouseEvent e)
		{
			if (e.isPopupTrigger())
			{
				AWSJTree tree = (AWSJTree) e.getSource();
				TreePath path = tree.getPathForLocation(e.getX(), e.getY());
				tree.setSelectionPath(path);
				if (path != null)
				{
					DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
					if (node.equals(SIMPLE_DB_NODE))
					{
						simpleDBPopupMenu.show(e.getComponent(), e.getX(), e.getY());
					}
					else if (node instanceof DomainMutableTreeNode)
					{
						domainNodeInPopup = (DomainMutableTreeNode) node;
						domainPopupMenu.show(e.getComponent(), e.getX(), e.getY());
					}
				}
			}
		}

	}
}
